<?php

namespace App\Http\Controllers\Postalapi;

use App\Http\Controllers\Controller;
use App\Models\BookHomeOrder;
use App\Models\BookHomePostalRev;
use Illuminate\Support\Facades\Log;

class Postal
{
    protected $config;
    protected $orderModel = null;

    public function __construct()
    {
        $this->config = config('other.postal');
        $this->orderModel = new BookHomeOrder();
    }

    /**下单取号 获取邮递单号 
     * @param order_id int 订单id
     * @param sender_address array 发件人信息
     * @param receiver_address array 收件人信息
     * array(
     *  'username' => '',
        'tel' => '',
        'province' => '',
        'city' => '',
        'district' => '',
        'address' => '',
     * )
     */
    public function setOrder($order_id = null, $sender_address, $receiver_address)
    {
        $order_id = $order_id ? $order_id : request()->order_id;

        if (!$order_id) {
            return ['code' => '201', 'msg' => '参数错误', 'data' => ''];
        }

        $order = $this->orderModel->find($order_id);

        if (!$order) {
            return ['code' => '201', 'msg' => '参数错误', 'data' => ''];
        }

        if (!$sender_address) {
            return ['code' => '201', 'msg' => '请填写发件人信息', 'data' => ''];
        }

        if (!$receiver_address) {
            return ['code' => '201', 'msg' => '请填写收件人信息', 'data' => ''];
        }

        $controllerObj = new Controller();

        /*检查是否合法地址*/
        $map1 = $controllerObj->getLonLatByAddress($sender_address['province'] . $sender_address['city'] . $sender_address['district'] . $sender_address['street'] . $sender_address['address']);

        if (isset($map1['code']) && $map1['code'] == 202) {
            return ['code' => '202', 'msg' => '发件人邮递地址不存在,请重新填写', 'data' => ''];
        }

        $map2 = $controllerObj->getLonLatByAddress($receiver_address['province'] . $receiver_address['city'] . $receiver_address['district'] . $receiver_address['street'] . $receiver_address['address']);

        if (isset($map2['code']) && $map2['code'] == 202) {
            return ['code' => '202', 'msg' => '收件人邮递地址不存在,请重新填写', 'data' => ''];
        }

        $book_list = $order->getOrderBookInfo;

        if (!$book_list) {
            return ['code' => '202', 'msg' => '邮递书籍不存在', 'data' => ''];
        }

        $book_data = [];
        foreach ($book_list as $key => $value) {
            $book_data["Cargo[$key]"] = [
                'cargo_name' => $value->book_name,
            ];
        }

        /**构造原始数据 */
        $xml_array = [
            'created_time' => date("Y-m-d H:i:s", time()),
            'logistics_provider' => config($this->config . '.logistics_provider'),
            'sender_type' => config($this->config . '.sender_type'),
            'inner_channel' => config($this->config . '.inner_channel'),
            'ecommerce_no' => config($this->config . '.ecommerce_no'),
            'sender_no' => config($this->config . '.sender_no'),
            'ecommerce_user_id' => config($this->config . '.ecommerce_no'),
            'logistics_order_no' => $order->order_number, //本系统订单号
            'base_product_no' => config($this->config . '.base_product_no'),
            'biz_product_no' => config($this->config . '.biz_product_no'),
            'sender' => [
                'name' => $sender_address['username'],
                'mobile' => $sender_address['tel'],
                'prov' => $sender_address['province'],
                'city' => $sender_address['city'],
                'county' => $sender_address['district'],
                'address' => $sender_address['street'] . $sender_address['address'],
            ], //发件方地址
            'receiver' => [
                'name' => $receiver_address['username'],
                'mobile' => $receiver_address['tel'],
                'prov' => $receiver_address['province'],
                'city' => $receiver_address['city'],
                'county' => $receiver_address['district'],
                'address' => $receiver_address['street'] . $receiver_address['address'],
            ], //收件方地址
            'cargos' => $book_data //邮递物品详情
        ];

        /**转化为xml数据 */
        $xml_data = $this->arrayToXml($xml_array);
        $xml_data = '<OrderNormal>' . $xml_data . '</OrderNormal>';

        Log::channel('postallog')->debug($xml_array);
        Log::channel('postallog')->debug($xml_data);


        /**签名 */
        $xml_sign_data = $this->xmlSign($xml_data, config($this->config . '.sign_str'));

        $post_data = [
            'logistics_interface' => urlencode($xml_data),
            'data_digest' => urlencode($xml_sign_data),
            'msg_type' => 'ORDERCREATE',
            'ecCompanyId' => config($this->config . '.ecommerce_no')
        ];
        Log::channel('postallog')->debug($post_data);

        $url = config($this->config . '.order_url');

        $temp = [];
        foreach ($post_data as $key => $value) {
            $temp[] = $key . '=' . $value;
        }

        $url = $url . '?' . implode('&', $temp);

        Log::channel('postallog')->debug($url);

        /**请求接口 */
        $res_xml = $this->postData($url, []);



        // var_dump($res_xml);exit;

        /**解析 */
        $res_array = $this->xmlToArray($res_xml);

        if (!$res_array) {
            Log::channel('postallog')->debug('下单接口解析失败：' . $res_xml);
            return ['code' => 202, 'msg' => '接口请求失败', 'data' => ''];
        }

        if (!$res_array['responseItems']['response']['success'] || $res_array['responseItems']['response']['success'] == 'false') {
            Log::channel('postallog')->debug('下单接口解析失败：' . json_encode($res_array, JSON_UNESCAPED_UNICODE));
            return ['code' => 202, 'msg' => $res_array['responseItems']['response']['reason'] ? $res_array['responseItems']['response']['reason'] : $this->getErrorMessage($res_array['responseItems']['response']['reason']), 'data' => ''];
        }

        return ['code' => 200, 'msg' => '成功', 'data' => ['waybill_no' => $res_array['responseItems']['response']['waybill_no'], 'order_id' => $order_id]];
    }

    /**打印电子面单(获取分拣码) 
     * @param order_id int 订单id
     * @param sender_address array 发件地址信息
     * @param receiver_address array 收件地址信息
     * array(
        'province' => '',
        'city' => '',
        'district' => '',
        'address' => '',
     * )
     * 
     */
    public function printElectronicSheet($order_id = null, $sender_address = null, $receiver_address = null)
    {
        $order_id = $order_id ? $order_id : request()->order_id;

        if (!$order_id) {
            return ['code' => '201', 'msg' => '参数错误', 'data' => ''];
        }

        $order = $this->orderModel->find($order_id);

        if (!$order) {
            return ['code' => '201', 'msg' => '参数错误', 'data' => ''];
        }

        if (!$sender_address) {
            return ['code' => '201', 'msg' => '请填写发件地址信息', 'data' => ''];
        }

        if (!$receiver_address) {
            return ['code' => '201', 'msg' => '请填写收件地址信息', 'data' => ''];
        }

        $body = [
            [
                'objectId' => $order->tracking_number,
                "senderAddress" => [
                    'province' => $sender_address['province'],
                    'city' => $sender_address['city'],
                    'area' => $sender_address['district'],
                    'detail' => $sender_address['street'] . $sender_address['address'],
                ],
                "receiverAddress" => [
                    'province' => $receiver_address['province'],
                    'city' => $receiver_address['city'],
                    'area' => $receiver_address['district'],
                    'detail' => $receiver_address['street'] . $receiver_address['address'],
                ],
            ]
        ];

        $post_data = [
            'wpCode' => config($this->config . '.wp_code'),
            'dataDigest' => config($this->config . '.sheet_digest'),
            'logisticsInterface' => json_encode($body)
        ];

        /**sdk参数 */
        $api =  config($this->config . '.sheet_name');
        $version = config($this->config . '.version');
        $ak = config($this->config . '.ak');
        $sk = config($this->config . '.sk');
        $url = config($this->config . '.sheet_url');

        $phpCaller = new HttpCaller();

        try {
            $result = $phpCaller->doPost($url, $post_data, $api, $version, $ak, $sk);

            $result_array = json_decode($result, true);

            if (isset($result_array['code']) && $result_array['code'] == 200) {
                return ['code' => 200, 'msg' => '成功', 'data' => $result_array['body']['result']];
            } else {
                return ['code' => 202, 'msg' => $result_array['message'], 'data' => ''];
            }
        } catch (\Exception $e) {

            return ['code' => '202', 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    /**
     * 轨迹查询 
     * @param order_id int 订单id
     * @param tracking_number int 运单号
     */
    public function travel($order_id = null, $tracking_number = null)
    {

        $order_id = $order_id ? $order_id : request()->order_id;
        $tracking_number = $tracking_number ? $tracking_number : request()->tracking_number;

        if (!$order_id && !$tracking_number) {
            return ['code' => '201', 'msg' => '参数错误', 'data' => ''];
        }

        if (empty($tracking_number)) {
            $order = $this->orderModel->where('order_number', $order_id)->where('is_pay', 8)->first();
            $trace_no = $order->tracking_number;
        } else {
            $order = $this->orderModel->where('tracking_number', $tracking_number)->where('is_pay', 8)->first();
            $trace_no = $tracking_number;
        }

        if (!$order) {
            return ['code' => '201', 'msg' => '参数错误', 'data' => ''];
        }
        if (!$trace_no) {
            return ['code' => 200, 'msg' => 'ok', 'data' => ''];
        }

        $url =  config($this->config . '.travel_url');
        $body = json_encode([
            'traceNo' => $trace_no
        ]);

        $url_params = [
            'sendID' => config($this->config . '.send_id'),
            'proviceNo' => config($this->config . '.provice_no'),
            'msgKind' => config($this->config . '.msg_kind'),
            'serialNo' => $order->order_number,
            'sendDate' => date("YmdHis", time()),
            'receiveID' => config($this->config . '.recieve_id'),
            'batchNo' => config($this->config . '.bath_no'),
            'dataType' => config($this->config . '.data_type'),
            'dataDigest' => $this->jsonSign($body),
            'msgBody' => urlencode($body)
        ];

        $temp = [];
        foreach ($url_params as $key => $value) {
            $temp[] = $key . '=' . $value;
        }

        $url = $url . '?' . implode('&', $temp);

        $res = $this->postData($url, [], true);

        if ($res['errorDesc'] != '查询结果正常返回！') {
            return ['code' => 202, 'msg' => $res['errorDesc'], 'data' => ''];
        } else {
            return ['code' => 200, 'msg' => 'ok', 'data' => $res['responseItems']];
        }
    }

    /**轨迹推送接收 */
    public function travelRecievd()
    {
        $re_data = file_get_contents("php://input");

        Log::channel('postallog')->debug("接收到邮政:\r\n" . $re_data);

        $params = $this->getParams($re_data);

        if ($params['msgKind'] != config($this->config . '.msg_receive_kind')) {
            Log::channel('postallog')->debug("接收到邮政轨迹：推送标识错误");
            return ['receiveID' => config($this->config . '.ecommerce_no'), 'responseState' => false, 'errorDesc' => '推送标识错误', 'responseItems' => []];
        }

        if ($params['dataDigest'] != $this->jsonSign(urldecode($params['msgBody']))) {
            Log::channel('postallog')->debug("接收到邮政轨迹：验签失败");
            return ['receiveID' => config($this->config . '.ecommerce_no'), 'responseState' => false, 'errorDesc' => '验签失败', 'responseItems' => []];
        }

        $data_json = urldecode($params['msgBody']);
        $data_array = json_decode($data_json, true);

        if (!is_array($data_array)) {
            Log::channel('postallog')->debug("接收到邮政轨迹：轨迹信息解析失败");
            return ['receiveID' => config($this->config . '.ecommerce_no'), 'responseState' => false, 'errorDesc' => '轨迹信息解析失败', 'responseItems' => []];
        }

        if (count($data_array['traces']) <= 0) {
            Log::channel('postallog')->debug("接收到邮政轨迹：无轨迹信息");
            return ['receiveID' => config($this->config . '.ecommerce_no'), 'responseState' => false, 'errorDesc' => '无轨迹信息', 'responseItems' => []];
        }

        $response_array = [];

        $opCode = 0;

        foreach ($data_array['traces'] as $key => $value) {
            $temp = [];
            $temp['traceNo'] = $value['traceNo'];
            $temp['success'] = true;
            $temp['reason'] = '';
            $response_array[] = $temp;
            $opCode = $value['opCode'];
        }

        $data = [
            'send_id' => $params['sendID'],
            'provice_no' => $params['proviceNo'],
            'msg_kind' => $params['msgKind'],
            'serial_no' => $params['serialNo'],
            'receive_id' => $params['receiveID'],
            'batch_no' => $params['batchNo'],
            'data_type' => $params['dataType'],
            'data_digest' => $params['dataDigest'],
            'trace_no' => $data_array['traces'][0]['traceNo'],
            'trace_content' => json_encode($data_array['traces']),
            'receive_content' => json_encode($params),
        ];

        $bookHomePostalRev = new BookHomePostalRev();
        $bookHomePostalRev->add($data);

        $order = $this->orderModel->where('tracking_number', $data_array['traces'][0]['traceNo'])->find();

        if ($order) {
            if ($order->is_sign == 1 && $opCode == 10) {
                $order->is_sign = 2;
                $order->save();
            }

            if ($order->is_sign == 2 && $opCode == 70) {
                $order->is_sign = 3;
                $order->save();
            }

            if ($order->is_sign == 3 && $opCode == 80) {
                $order->is_sign = 4;
                $order->save();
                // $purchase_model = New \app\common\model\PurchaseModel();
                // $purchase = $purchase_model->where('order_number',$order->order_number)->find();
                // $purchase->create_time = date("Y-m-d H:i:s",time());
            }

            if ($order->is_sign == 3 && $opCode == 20) {
                $order->is_sign = 5;
                $order->save();
            }
        }

        return ['receiveID' => config($this->config . '.ecommerce_no'), 'responseState' => true, 'errorDesc' => '', 'responseItems' => $response_array];
    }

    //数组转换成xml
    private function arrayToXml($arr)
    {
        $xml = '';
        foreach ($arr as $key => $val) {
            $key = preg_replace('/\[\d*\]/', '', $key);
            if (is_array($val)) {
                $xml .= "<" . $key . ">" . $this->arrayToXml($val) . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            }
        }
        return $xml;
    }

    //xml转换成数组
    private function xmlToArray($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
        return $val;
    }

    /**post http */
    public static function postData($url, $data, $decode = false, $assoc = true, $ssl = false)
    {

        $jsonData = json_encode($data, JSON_UNESCAPED_UNICODE);
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $ssl);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $ssl);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        // curl_setopt($curl, CURLOPT_HTTPHEADER, [
        //     'application/x-www-form-urlencoded; charset=UTF-8',
        //     'Content-Length: ' . strlen($jsonData)
        // ]);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData);

        $rawData = curl_exec($curl);
        $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        // curl_close($curl);
        // var_dump($httpcode);

        if ($decode) {
            return json_decode($rawData, $assoc);
        } else {
            return $rawData;
        }
    }

    /**get http */
    public static function getData($url, $decode = true, $assoc = true, $ssl = false)
    {

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $ssl);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $ssl);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

        $rawData = curl_exec($curl);

        // var_dump($rawData);exit;

        curl_close($curl);

        if ($decode) {
            return json_decode($rawData, $assoc);
        } else {
            return $rawData;
        }
    }

    /**对xml数据签名 */
    public function xmlSign($data, $partnered)
    {
        $str = pack('H*', md5($data . $partnered)); //MD5后二进制化
        $md5Array = $this->getbytes($str); //转化为字节数组
        return \app\postalapi\controller\BaseEncode::encode($md5Array);
        /**对应java的sun.misc */
    }

    /**对json数据签名 */
    public function jsonSign($data)
    {
        return \base64_encode(md5($data . config($this->config . '.sign_str2')));
    }

    public function jsonSign2($data)
    {
        $str = md5($data . config($this->config . '.sign_str2'));
        // return $str;

        return base64_encode($str);
        // var_dump($str);exit;
        // $md5Array = $this->getbytes($str);//转化为字节数组

        // return \app\postalapi\controller\BaseEncode::encode($md5Array);/**对应java的sun.misc */
    }

    /**
     * 电商Sign签名生成
     * @param data 内容   
     * @param appkey Appkey
     * @return DataSign签名
     */
    function encrypt($data)
    {
        // var_dump(config($this->config.'.sign_str2'));exit;
        return base64_encode(md5($data . config($this->config . '.sign_str2')));
    }

    // function java_base64_encode($data){

    //     $str = md5($data . config($this->config.'.sign_str2'));

    //     return new SecretKeySpec($str, "DES");

    //     // $arr = $this->getbytes($str);//转化为字节数组

    //     // $str = '';
    //     // foreach ($arr as $key => $value) {
    //     //     $str .= is_numeric($value)? chr($value) : $value;
    //     // }

    //     // return base64_encode($str);
    // }

    /**错误码对照表 */
    public function getErrorMessage($code)
    {
        switch ($code) {
            case 'B00':
                return '未知业务错误';
                break;
            case 'B01':
                return '关键字段缺失';
                break;
            case 'B02':
                return '关键数据格式不正确';
                break;
            case 'B03':
                return '没有找到请求的数据';
                break;
            case 'B04':
                return '当前数据状态不能进行该项操作';
                break;
            case 'B98':
                return '数据保存失败';
                break;
            case 'B05':
                return '号段获取失败';
                break;
            case 'S01':
                return '非法的XML/JSON';
                break;
            case 'S02':
                return '非法的数字签名';
                break;
            case 'S03':
                return '非法的物流公司/仓储公司';
                break;
            case 'S04':
                return '非法的通知类型';
                break;
            case 'S05':
                return '非法的通知内容';
                break;
            case 'S06':
                return '网络超时，请重试';
                break;
            case 'S07':
                return '系统异常，请重试';
                break;
            case 'S08':
                return 'HTTP状态异常（非200）';
                break;
            case 'S09':
                return '返回报文为空';
                break;
            case 'S10':
                return '找不到对应的网关信息';
                break;
            case 'S11':
                return '非法的网关信息';
                break;
            case 'S12':
                return '非法的请求参数';
                break;

            case 'S13':
                return '业务服务异常';
                break;
            default:
                return '未知错误';
                break;
        }
    }

    /**
    
     * 转换一个String字符串为byte数组
    
     * @param $str 需要转换的字符串
    
     * @param $bytes 目标byte数组
    
     * @author Zikie
    
     */
    public static function getBytes($str)
    {

        $len = strlen($str);

        $bytes = array();

        for ($i = 0; $i < $len; $i++) {

            if (ord($str[$i]) >= 128) {

                $byte = ord($str[$i]) - 256;
            } else {

                $byte = ord($str[$i]);
            }

            $bytes[] =

                $byte;
        }

        return $bytes;
    }

    public function getParams($data)
    {

        if (!$data) {
            return [];
        }
        $data = str_replace("{", '', $data);
        $data = str_replace("}", '', $data);
        $data = str_replace(" ", '', $data);
        $data = str_replace('"', '', $data);
        $data = explode(',', $data);
        $res = [];

        foreach ($data as $key => $value) {
            $value_array = explode(":", $value);
            $res[$value_array[0]] = $value_array[1];
        }
        return $res;
    }
}



